package cleancode.controller.interpreter;

import cleancode.model.Operation;
import cleancode.model.UltraUser;
import cleancode.util.StringUtils;

/**
 * Interprete the command user input according to the rule, we can define other rules of command and implement it.
 */
public class DefaultCommandInterpreter implements CommandInterpreter
{
    public String getRule()
    {
        StringBuilder builder = new StringBuilder();
        builder.append( StringUtils.rightPadding( "h" ) + ": Get help menu.\n" );
        builder.append( StringUtils.rightPadding( "suUserName" ) + ": Switch to user.\n" );
        builder.append( StringUtils.rightPadding( "+uUserName1[, UserName2...]" ) + ": Add a new user.\n" );
        builder.append( StringUtils.rightPadding( "+rRoleName1[, RoleName2...]" ) + ": Add a new role.\n" );
        builder.append( StringUtils.rightPadding( "+oOperationName1[, OperationName2...]" ) +
            ": Add a new operation.\n" );
        builder.append( StringUtils.rightPadding( "+rRoleName1[, RoleName2...]->UserName1[, UserName2...]" ) +
            ": Add new roles to given users. If roles/users don't exist they'll be created.\n" );
        builder.append( StringUtils.rightPadding( "+oOperationName1[, OperationName2...]" ) +
            ": Add new operations to given roles. If operations/roles don't exist they'll be created.\n" );
        builder.append( StringUtils.rightPadding( "-uUserName1[, UserName2...]" ) + ": Remove a user.\n" );
        builder.append( StringUtils.rightPadding( "-rRoleName1[, RoleName2...]" ) + ": Remove a role.\n" );
        builder.append( StringUtils.rightPadding( "-oOperationName1[, OperationName2...]" ) +
            ": Remove an operation.\n" );
        builder.append( StringUtils.rightPadding( "-rRoleName1[, RoleName2...]->UserName1[, UserName2...]" ) +
            ": Remove roles from given users. If roles/users don't exist then do nothing.\n" );
        builder.append( StringUtils.rightPadding( "-oOperationName1[, OperationName2...]" ) +
            ": Remove operations from given roles. If operations/roles don't exist then do nothing.\n" );
        builder.append( StringUtils.rightPadding( "lu" ) + ": List all users.\n" );
        builder.append( StringUtils.rightPadding( "lr" ) + ": List all roles.\n" );
        builder.append( StringUtils.rightPadding( "lo" ) + ": List all operations.\n" );
        builder.append( StringUtils.rightPadding( UltraUser.ULTRA_USER_NAME ) + ": Login as ultra user.\n" );
        return builder.toString();
    }

    public CommandInfo interprete( String command )
    {
        CommandInfo commandInfo = new CommandInfo( command );

        if( command.charAt( 0 ) == '+' || command.charAt( 0 ) == '-' )
        {
            interpreteStoredDataCommand( commandInfo );
        }
        else if( command.startsWith( "su" ) )
        {
            if( command.equals( "su" ) )
            {
                commandInfo.setErrorMessage( "User name missing!" );
            }
            else
            {
                commandInfo.setOperation( new Operation( "switchUser" ) );
                commandInfo.setArgs( new Object[]{ command.substring( 2 ) } );
            }
        }
        else
        {
            interpreteSimpleCommand( commandInfo );
        }

        return commandInfo;
    }

    /**
     * Interprete +/-u/r/o operations
     */
    private void interpreteStoredDataCommand( CommandInfo commandInfo )
    {
        String command = commandInfo.getCommand();
        if( command.length() < 3 || "".equals( getFullNameForShortCut( command.charAt( 1 ) ) ) )
        {
            commandInfo.setErrorMessage( "Invalid command!" );
            return;
        }

        StringBuilder operationBuilder = new StringBuilder();
        Object[] args;
        operationBuilder.append( command.charAt( 0 ) == '+' ? "add" : "remove" ).append(
            getFullNameForShortCut( command.charAt( 1 ) ) );
        int arrowIndex = command.indexOf( "->" );
        if( arrowIndex != -1 )
        {
            operationBuilder.append( command.charAt( 0 ) == '+' ? "To" : "From" );
            String source = command.substring( 2, arrowIndex );
            String dist = command.substring( arrowIndex + 2 );
            if( isParameterEmpty( source ) || isParameterEmpty( dist ) )
            {
                commandInfo.setErrorMessage( "Command parameter empty!" );
                return;
            }
            args = new Object[]{ source.split( "," ), dist.split( "," ) };
        }
        else
        {
            args = new Object[]{ command.substring( 2 ).split( "," ) };
        }
        commandInfo.setOperation( new Operation( operationBuilder.toString() ) );
        commandInfo.setArgs( args );
    }

    private boolean isParameterEmpty( String input )
    {
        return StringUtils.trimComma( input ).trim().length() == 0;
    }

    private void interpreteSimpleCommand( CommandInfo commandInfo )
    {
        String operation;
        switch( commandInfo.getCommand() )
        {
            case "h":
                operation = "help";
                break;
            case "lu":
                operation = "listUser";
                break;
            case "lr":
                operation = "listRole";
                break;
            case "lo":
                operation = "listOperation";
                break;
            default:
                operation = commandInfo.getCommand();
        }
        commandInfo.setOperation( new Operation( operation ) );
    }

    private String getFullNameForShortCut( char c )
    {
        String fullName;
        switch( c )
        {
            case 'u':
                fullName = "User";
                break;
            case 'r':
                fullName = "Role";
                break;
            case 'o':
                fullName = "Operation";
                break;
            default:
                fullName = "";
        }
        return fullName;
    }

}
